package com.lry.jvm.instructions.refrences;

import com.lry.jvm.instructions.base.ClassInit;
import com.lry.jvm.instructions.base.Index16Instruction;
import com.lry.jvm.rtda.Frame;
import com.lry.jvm.rtda.LocalVars;
import com.lry.jvm.rtda.OperandStack;
import com.lry.jvm.rtda.heap.*;
import com.lry.jvm.util.Util;

public class putstatic extends Index16Instruction {

    @Override
    public byte getOpCode() {
        return (byte) 0xb3;
    }

    @Override
    public void execute(Frame frame) {
        JMethod method = frame.getMethod();
        JClass jClass = method.getJClass();
        RuntimeConstantPool rcp = jClass.getConstantPool();

        FieldRef fieldRef = (FieldRef) rcp.getConstant(index);
        JField field = fieldRef.resolvedField();
        JClass fieldClass = field.getJClass();

        if(!fieldClass.isInitStarted()){
            frame.revertNextPc();
            ClassInit.initClass(frame.getThread(),fieldClass);
            return;
        }

        if (!field.isStatic()) {
            Util.panic("java.lang.IncompatibleClassChangeError");
        }

        if (field.isFinal()) {
            if (jClass != fieldClass || !method.getName() .equals("<clinit>")) {
                Util.panic("java.lang.IllegalAccessError");
            }
        }

        String descriptor = field.getDescriptor();
        int slotId = field.getSlotId();
        LocalVars slots = fieldClass.getStaticVars();
        OperandStack stack = frame.getOperandStack();
        //栈->局部变量表
        switch (descriptor.charAt(0)){
            case 'Z':
            case 'B':
            case 'C':
            case 'S':
            case 'I':
                slots.setInt(slotId,stack.popInt());
                break;
            case 'F':
                slots.setFloat(slotId,stack.popFloat());
                break;
            case 'J':
                slots.setLong(slotId,stack.popLong());
                break;
            case 'D':
                slots.setDouble(slotId,stack.popDouble());
                break;
            case '[':
            case 'L':
                slots.setRef(slotId,stack.popRef());
                break;
        }
    }
}
